/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.component.util.comparators;

import java.util.Comparator;

import robocup.component.geometry.Vektor;
import robocup.component.worldobjects.Player;

/**
 * This comparator can be used for comparing players in different dimensions
 * (attributes).
 */
public class PlayerComparator implements Comparator<Player> {

	public enum ORDER {
		ASCENDING, DESCENDING
	};

	public enum DIMENSION {
		X_AXIS, Y_AXIS, DISTANCE, X_AXIS_ABSOLUTE, Y_AXIS_ABSOLUTE, ROLE, ANGLE
	};

	private ORDER order = ORDER.ASCENDING;

	private DIMENSION dimension;

	private Vektor position;

	/**
	 * An object, which can compare players with each other along some defined
	 * dimensions
	 * 
	 * @param d -
	 *            the dimension, by which the players should be compared (one of
	 *            X_AXIS, Y_AXIS, DISTANCE, X_AXIS_ABSOLUTE, Y_AXIS_ABSOLUTE,
	 *            ROLE, ANGLE)
	 */
	public PlayerComparator(DIMENSION d) {
		this.dimension = d;
	}

  /*
   * (non-Javadoc)
   * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
   */
	public int compare(Player o1, Player o2) {

		if (o1 == null) {
			return 1;
		}

		if (o2 == null) {
			return 1;
		}

		int compareValue = 0;
		switch (this.dimension) {
		case X_AXIS:
			compareValue = this.compareX(o1, o2);
			break;
		case Y_AXIS:
			compareValue = this.compareY(o1, o2);
			break;
		case DISTANCE:
			compareValue = this.comparePos(o1, o2);
			break;
		case X_AXIS_ABSOLUTE:
			compareValue = this.compareXAbs(o1, o2);
			break;
		case Y_AXIS_ABSOLUTE:
			compareValue = this.compareYAbs(o1, o2);
			break;
		case ROLE:
			compareValue = this.compareRole(o1, o2);
			break;
		case ANGLE:
			compareValue = this.compareAngle(o1, o2);
			break;

		}

		if (this.order == ORDER.ASCENDING)
			compareValue *= -1;
		return compareValue;
	}

	/**
	 * sort players by angle. 0 to 360 degree.
	 * 
	 * @param o1
	 * @param o2
	 * @return
	 */
	private int compareAngle(Player o1, Player o2) {

		if (o1.getNumber() == o2.getNumber())
			return 0;

		double angle1 = this.position.getAngleTo(o1.getPosition());
		if (angle1 < 0)
			angle1 += 360.0;

		double angle2 = this.position.getAngleTo(o2.getPosition());
		if (angle2 < 0)
			angle2 += 360;

		if (angle1 > angle2)
			return -1;

		return 1;
	}

	/**
	 * @param o1
	 * @param o2
	 * @return
	 */
	private int compareRole(Player o1, Player o2) {

		if (o1.getNumber() > o2.getNumber())
			return -1;

		if (o1.getNumber() == o2.getNumber())
			return 0;

		return 1;
	}

	/**
	 * Compares distance of 2 players to a point.
	 */
	private int comparePos(Player o1, Player o2) {
		if (this.position == null) {
			return 0;
		}
		if (o1.getDistance(this.position) > o2.getDistance(this.position))
			return -1;
		return 1;
	}

  /**
   * Compares the position.x attribute of 2 players.
   */
	public int compareX(Player o1, Player o2) {

		if (o1.getPosition().getX() > o2.getPosition().getX())
			return -1;

		return 1;
	}

  /**
   * Compares the abs(position.x) attribute of 2 players.
   */
	public int compareXAbs(Player o1, Player o2) {

		if (Math.abs(o1.getPosition().getX()) > Math.abs(o2.getPosition()
				.getX()))
			return -1;

		return 1;
	}

  /**
   * Compares the abs(position.y) attribute of 2 players.
   */
	public int compareYAbs(Player o1, Player o2) {

		if (Math.abs(o1.getPosition().getY()) > Math.abs(o2.getPosition()
				.getY()))
			return -1;

		return 1;
	}

  /**
   * Compares the position.y attribute of 2 players.
   */
	public int compareY(Player o1, Player o2) {

		if (o1.getPosition().getY() > o2.getPosition().getY())
			return -1;

		return 1;
	}

	/**
	 * @return Returns the dimension.
	 */
	public DIMENSION getDimension() {

		return this.dimension;
	}

	/**
	 * @param dimension
	 *            The dimension to set.
	 */
	public void setDimension(DIMENSION dimension) {

		this.dimension = dimension;
	}

	/**
	 * @param dimension
	 *            The dimension to set.
	 */
	public void setPosition(Vektor pos) {
		this.position = pos;
	}

	/**
	 * This method sets the order type!
	 * 
	 * @param order -
	 *            <ORDER>, either ascending or descending
	 */
	public void setOrder(ORDER order) {
		if (order != null)
			this.order = order;
	}

}
